###########################################################################
#	$Id: Object.p 39 2008-11-15 09:31:06Z donbeave $
###########################################################################

@CLASS
Object

@OPTIONS
locals
partial

@USE
bLib.p



###########################################################################
#	Options:
#		$.SQL_OBJECT[object]
#		$.TABLES_PREFIX[string]
#		$.PROCESSES_PATH[string]
@create[hshParams]
^if(def $hshParams.SQL_OBJECT){
	$self.SQL_OBJECT[$hshParams.SQL_OBJECT]
}{
	^throw[${CLASS_NAME}.spec;^$.SQL_OBJECT;option not specified]
}

^if(def $hshParams.TABLES_PREFIX){
	$self.TABLES_PREFIX[^hParams.TABLES_PREFIX.trim[]]
}

$self.TABLES[
	$.objects[${TABLES_PREFIX}objects]
	$.objects_types[${TABLES_PREFIX}objects_types]
	$.objects_texts[${TABLES_PREFIX}objects_texts]
	$.data_types[${TABLES_PREFIX}data_types]
	$.blocks[${TABLES_PREFIX}blocks]
	$.blocks_to_objects[${TABLES_PREFIX}blocks_to_objects]
	$.processes[${TABLES_PREFIX}processes]
	$.processes_types[${TABLES_PREFIX}processes_types]
]

^self._declareVars[]

^if(def $hParams.PROCESSES_PATH){
	$PROCESSES_PATH[^bLib:preparePath[$hParams.PROCESSES_PATH]]
}
#end @create[]



@_declareVars[]
$self.OBJECTS[^hash::create[]]
$self.OBJECTS_TYPES[^hash::create[]]
$self.PROCESSES[^hash::create[]]
$self.BLOCKS[^hash::create[]]

$self.OBJECT_ID(0)
$self.SPECIAL_LOCALE(255)

$self.ADDITIONAL_FIELDS[^table::create{select	update	field}]
$self.TEXTS_ADDITIONAL_FIELDS[^table::create{select	update	field}]
#end @_declareVars[]



###########################################################################
#	Options:
#		$.id(int)
#		$.force(bool) = false
#		$.data[string]
#		$.SQL_SELECT
#		$.SQL_FROM
#		$.SQL_WHERE
#		$.SQL_additional
#		$.add_to_hash(bool) = true
#	Result: table/hash
@getObjects[hshParams;hshSqlOptions;hshCacheOptions]
$hParams[^hash::create[$hshParams]]

^if(^hParams.id.int(0) && $self.OBJECTS.[^hParams.id.int(0)] && !^hParams.force.bool(false)){
	$result[$self.OBJECTS.[^hParams.id.int(0)]]
}{
	$result[^self.SQL_OBJECT.table{
		SELECT
			main.object_id AS id,
			main.sort_order,
			^if($hParams.data ne "minimal"){
				main.thread_id,
				main.object_process_id AS process_id,
				main.object_type_id AS type_id,
				main.dt_update,
			}
			main.parent_id
			^if($hParams.data ne "minimal"){
				^self.ADDITIONAL_FIELDS.menu{
					, $self.ADDITIONAL_FIELDS.fields.select ^if(def $self.ADDITIONAL_FIELDS.field){ AS $self.ADDITIONAL_FIELDS.field}
				}
			}
			^if(def $hParams.SQL_SELECT){
				, $hParams.SQL_SELECT
			}
		FROM
			$TABLES.objects main
			^if(def $hParams.SQL_FROM){
				
				^if(!^hParams.SQL_FROM.match[^^[\s\t]* (LEFT|RIGHT)][isx]){
					, 
				}
				
				$hParams.SQL_FROM
			}
		WHERE
			^if(^hParams.id.int(0)){
				main.object_id = ^hParams.id.int(0) AND
			}
			^if(def $hParams.SQL_WHERE){
				($hParams.SQL_WHERE)
			}{
				1=1
			}
		$hParams.SQL_additional
	}[
		^hash::create[$hshSqlOptions]
	][
		^hash::create[$hshCacheOptions]
	]]

	^if($result && ^hParams.add_to_hash.bool(true)){
		^if($self.OBJECTS.table is "table"){
			$tNew[^result.select(!$self.OBJECTS.[$result.id])]
			
#			adding new loaded objects to hash
			^self.OBJECTS.add[^tNew.hash[id]]
			
			^self.OBJECTS.table.join[$tNew]
			
			^self.OBJECTS.table.sort($self.OBJECTS.table.sort_order)[asc]
		}{
#			added all loaded objects to hash
			^self.OBJECTS.add[^result.hash[id]]
			
			$self.OBJECTS.table[$result]
		}
	}
}
#end @getObjects[]



###########################################################################
#	Options:
#		$.add_to_hash(bool) = true
#	Result: table
@getObjectsTypes[hshParams;hshSqlOptions;hshCacheOptions]
$hParams[^hash::create[$hshParams]]

$result[^self.SQL_OBJECT.table{
	SELECT
		object_type_id AS id,
		sort_order,
		is_fake,
		name
	FROM
		$self.TABLES.objects_types
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]

^if($result && ^hParams.add_to_hash.bool(true)){
	^self.OBJECTS_TYPES.add[^result.hash[id]]
}
#end @getObjectsTypes[]



###########################################################################
#	Options:
#		$.id(int)
#		$.ids[table]
#		$.locale_id(int)
#		$.SQL_SELECT
#		$.SQL_FROM
#		$.SQL_WHERE
#		$.SQL_additional
#		$.add_to_hash(bool) = true
#	Result: table
@getObjectsTexts[hshParams;hshSqlOptions;hshCacheOptions]
$hParams[^hash::create[$hshParams]]

$result[^self.SQL_OBJECT.table{
	SELECT
		main.locale_id,
		main.object_id AS id,
		main.name
		^self.TEXTS_ADDITIONAL_FIELDS.menu{
			, $self.TEXTS_ADDITIONAL_FIELDS.fields.select ^if(def $self.TEXTS_ADDITIONAL_FIELDS.field){ AS $self.TEXTS_ADDITIONAL_FIELDS.field}
		}
		^if(def $hParams.SQL_SELECT){
			, $hParams.SQL_SELECT
		}
	FROM
		$self.TABLES.objects_texts main
		^if(def $hParams.SQL_FROM){, $hParams.SQL_FROM}
	WHERE
		^if(^hParams.id.int(0)){
			main.object_id = ^hParams.id.int(0) AND
		}
		^if(def $hParams.ids && $hParams.ids is "table"){
			main.object_id IN (^hParams.ids.menu{$hParams.ids.id}[,]) AND
		}
		^if(^hParams.locale_id.int(0)){
			main.locale_id = ^hParams.locale_id.int(0) AND
		}
		^if(def $hParams.SQL_WHERE){
			($hParams.SQL_WHERE)
		}{
			1=1
		}
	$hParams.SQL_additional
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]

^if($result && ^hParams.add_to_hash.bool(true)){
	$hTextsByObject[^result.hash[id][$.type[table]	$.distinct(true)]]

	^hTextsByObject.foreach[iObjectID;tTexts]{
		$self.OBJECTS.[^iObjectID.int(0)].texts[^tTexts.hash[locale_id]]
	}
}
#end @getObjectsTexts[]



###########################################################################
#	Options:
#		$.object_id(int)
#		$.objects_ids[table]
#		$.type[string]
#		$.SQL_SELECT
#		$.SQL_FROM
#		$.SQL_WHERE
#		$.SQL_additional
#		$.add_to_hash(bool) = true
#	Result: table
@getBlocks[hshParams;hshSqlOptions;hshCacheOptions]
$hParams[^hash::create[$hshParams]]

^if(!$self.DATA_TYPES){
	$self.DATA_TYPES[^self.getDataTypes[]]
}

^if(^hParams.object_id.int(0)){
	$iObjectID(^hParams.object_id.int(^OBJECT_ID.int(0)))
}

$result[^self.SQL_OBJECT.table{
	SELECT
		main.block_id AS id,
		main.data_type_id,
		main.block_process_id AS process_id,
		main.is_not_empty,
		main.is_shared,
		main.is_parsed_manual,
		main.dt_update,
		main.name,
		main.params,
		main.data
		^if($iObjectID || $hParams.objects_ids){
			, ${TABLES.blocks_to_objects}.object_id,
			${TABLES.blocks_to_objects}.sort_order
		}
		^if(def $hParams.SQL_SELECT){
			, $hParams.SQL_SELECT
		}
	FROM
		^if($iObjectID || $hParams.objects_ids){
			$self.TABLES.blocks_to_objects,
		}
		$self.TABLES.blocks main
		^if(def $hParams.SQL_FROM){, $hParams.SQL_FROM}
	WHERE
		^if($iObjectID || $hParams.objects_ids){
			main.block_id = ${self.TABLES.blocks_to_objects}.block_id AND
			
			^if(def $hParams.objects_ids && $hParams.objects_ids is "table"){
				${TABLES.blocks_to_objects}.object_id IN (^hParams.objects_ids.menu{$hParams.objects_ids.id}[,]) AND
			}{
				${TABLES.blocks_to_objects}.object_id = $iObjectID AND
			}
		}
		^if(def $hParams.type){
			^if(^self.DATA_TYPES.locate[name;$hParams.type]){
				main.data_type_id = ^self.DATA_TYPES.id.int(0) AND
			}{
				^throw[${CLASS_NAME}.search;^$DATA_TYPES (name: $hParams.type);data type not found]
			}
		}
		^if(def $hParams.SQL_WHERE){
			($hParams.SQL_WHERE) AND
		}
		main.is_published = 1
	^if($iObjectID){
		ORDER BY ${self.TABLES.blocks_to_objects}.sort_order DESC
	}
	$hParams.SQL_additional
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]


^if($result && ^hParams.add_to_hash.bool(true) && ($iObjectID || $hParams.objects_ids)){
	
	$hBlocksByObject[^result.hash[object_id][
		$.type[table]
		$.distinct(true)
	]]
	
	^hBlocksByObject.foreach[iObjectID;tBlocks]{
		$self.BLOCKS.[$iObjectID][^hash::create[]]
		
		$self.BLOCKS.[$iObjectID].order[$tBlocks]
		
		$self.BLOCKS.[$iObjectID].is_Loaded(true)
	}
	
	
	^if($self.BLOCKS.table is "table"){
#		getting blocks by id
		$tBlocksByID[^self.BLOCKS.table.hash[id][
			$.type[table]
			$.distinct(true)
		]]
		
#		selecting newest blocks
		$tNew[^result.select(!$tBlocksByID.[$result.id])]
		
		^self.BLOCKS.table.join[$tNew]
	}{
		$self.BLOCKS.table[$result]
	}
}
#end @getBlocks[]



###########################################################################
#	Result: table
@getDataTypes[hshParams;hshSqlOptions;hshCacheOptions]
$hParams[^hash::create[$hshParams]]

$result[^self.SQL_OBJECT.table{
	SELECT
		data_type_id AS id,
		sort_order,
		name,
		description,
		update_script_id,
		edit_script_id
	FROM
		$self.TABLES.data_types
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]
#end @getDataTypes[]



###########################################################################
#	Options:
#		$.id(int)
#		$.name[string]
#	Result: table
@getDataType[hshParams]
$hParams[^hash::create[$hshParams]]

# loading data types if it is not loaded
^if(!$self.DATA_TYPES){
	$self.DATA_TYPES[^self.getDataTypes[]]
}

# getting data type by ID (if ID is specified and if id greater-than 0)
^if(^hParams.id.int(0)){
	^if(^self.DATA_TYPES.locate[id;^hParams.id.int(0)]){
		$result[$self.DATA_TYPES]
	}{
		^throw[${CLASS_NAME}.search;^$DATA_TYPES (id: ^hParams.id.int(0));data type not found]
	}
}{
#	trying to get data type by name
	^if(^self.DATA_TYPES.locate[name;$hParams.name]){
		$result[$self.DATA_TYPES]
	}{
		^throw[${CLASS_NAME}.search;^$DATA_TYPES (name: $hParams.name);data type not found]
	}
}
#eng @getDataType[]



###########################################################################
#	Options:
#		$.id(int)
#		$.SQL_SELECT
#		$.SQL_FROM
#		$.SQL_WHERE
#		$.SQL_additional
#		$.add_to_hash(bool) = true
#	Result: table
###########################################################################
@getProcesses[hshParams;hshSqlOptions;hshCacheOptions]
$hParams[^hash::create[$hshParams]]

^if(^hParams.id.int(0) && $self.PROCESSES.[^hParams.id.int(0)]){
	$result[$self.PROCESSES.[^hParams.id.int(0)]]
}{
	$result[^self.SQL_OBJECT.table{
		SELECT
			main.process_id AS id,
			main.sort_order,
			main.process_type_id AS type_id,
			main.dt_update,
			main.name,
			main.filename,
			main.description
			^if(def $hParams.SQL_SELECT){
				, $hParams.SQL_SELECT
			}
		FROM
			$self.TABLES.processes main
			^if(def $hParams.SQL_FROM){, $hParams.SQL_FROM}
		WHERE
			^if(^hParams.id.int(0)){
				main.process_id = ^hParams.id.int(0) AND
			}
			^if(def $hParams.SQL_WHERE){
				($hParams.SQL_WHERE)
			}{
				1=1
			}
		$hParams.SQL_additional
	}[
		^hash::create[$hshSqlOptions]
	][
		^hash::create[$hshCacheOptions]
	]]                                                 

	^if($result && ^hParams.add_to_hash.bool(true)){
		^self.PROCESSES.add[^result.hash[id]]
	}
}
#end @getProcesses[]



###########################################################################
#	Result: table
###########################################################################
@getProcessesTypes[hshParams;hshSqlOptions;hshCacheOptions]
$hParams[^hash::create[$hshParams]]

$result[^self.SQL_OBJECT.table{
	SELECT
		process_type_id AS id,
		sort_order,
		name
	FROM
		$self.TABLES.processes_types
}[
	^hash::create[$hshSqlOptions]
][
	^hash::create[$hshCacheOptions]
]]
#end @getProcessesTypes[]



###########################################################################
#	Options:
#		$.id(int)
#		$.locale_id(int) = 0
#	Result: int
@is_ValidObject[hshParams]
$hParams[^hash::create[$hshParams]]

$tObject[^self.getObjects[
	$.id(^hParams.id.int(0))
	$.add_to_hash(true)
]]

$result($tObject)

^if($tObject){
#	if specified a "Locale ID" getting object texts
	^if(^hParams.locale_id.int(0)){
		$tObjectTexts[^self.getObjectsTexts[
			$.id(^hParams.id.int(0))
#			$.is_published(1)
			$.add_to_hash(true)
		]]

		$self.OBJECTS.[$self.OBJECT_ID].texts[^tObjectTexts.hash[locale_id]]

		$result($tObject && $self.OBJECTS.[^hParams.id.int(0)].[^hParams.locale_id.int(0)])
	}
}
#end @is_ValidObject[]



@replaceCurrentObject[intObjectID]
$iObjectID(^intObjectID.int(0))

^if($self.OBJECT_ID == $iObjectID){
	^throw[Engine.duplicate;^$intObjectID (obj: $iObjectID, sys_obj: $self.OBJECT_ID);duplicate object]
}


# if object is loaded, changing variables
^if($OBJECTS.[$iObjectID]){
	$self.PREV_OBJECT_ID($OBJECT_ID)
	$self.OBJECT_ID($iObjectID)
}{

#	if isn't loaded, first getting data (check), after change variables
	^if(^self.is_ValidObject[$.id($iObjectID)]){

		$self.PREV_OBJECT_ID($OBJECT_ID)
		$self.OBJECT_ID($iObjectID)

	}{
		^throw[Engine.invalid;^$intObjectID (id: $intObjectID);invalid option]
	}

}
#end @replaceCurrentObject[]



@repairPreviousObject[]
^if(^self.PREV_OBJECT_ID.int(0)){

	$iCurrentObjectID($OBJECT_ID)

	$self.OBJECT_ID($PREV_OBJECT_ID)
	$self.PREV_OBJECT_ID($iCurrentObjectID)

}{
	^throw[Engine.define;^$PREV_OBJECT_ID;undefined variable]
}
#end @repairPreviousObject[]



###########################################################################
#	Result: string
@parseObject[intObjectID]
# if needed, changing current object
^if(^intObjectID.int($self.OBJECT_ID) != $self.OBJECT_ID){
	$iPreviousObjectID($OBJECT_ID)
	
	^self.replaceCurrentObject(^intObjectID.int($self.OBJECT_ID))
}

# disabling by default custom result of object
$self.PROCESS_HANDLED(false)

$tObject[$self.OBJECTS.[$self.OBJECT_ID]]

$sBlocksData[^self.parseObjectBlocks($self.OBJECT_ID)]

^if(def $sBlocksData){
	$sBlocksData[^sBlocksData.trim[]]
}

# if defined object's process, running it
^if(^tObject.process_id.int(0)){
	$sObjectProcessData[^self.runProcess(^tObject.process_id.int(0))]
}

# printing result
^if(^self.PROCESS_HANDLED.bool(false)){
	$result[$sObjectProcessData]
}{
	$result[${sBlocksData}$sObjectProcessData]
}

^if(^tObject.link_to_object_id.int(0)){
	$result[
		$result
		^self.parseObject(^tObject.link_to_object_id.int(0))
	]
}

^if(^iPreviousObjectID.int(0)){
	^self.replaceCurrentObject(^iPreviousObjectID.int(0))
}
#end @parseObject[]



@_getObjectTextData[intObjectID;intLocaleID]
$tTexts[$self.OBJECTS.[^intObjectID.int(0)].texts]

^if($tTexts){
	^if($tTexts.[$intLocaleID]){
		$result[$tTexts.[$intLocaleID]]
	}{
		$result[$tTexts.[$self.SPECIAL_LOCALE]]
	}
}

^if(!$result && ^self.OBJECTS.[^intObjectID.int(0)].link_to_object_id.int(0)){
	$result[^self._getObjectTextData(^self.OBJECTS.[^intObjectID.int(0)].link_to_object_id.int(0))]
}
#end @_getObjectTextData[]



###########################################################################
#	Options:
#		$.tag_name[string] = 'object'
#		$.tag_body[string]
#		$.locale_id(int) = $LOCALE_ID
#	Result: string
@printObject[altData;hshParams]
^if(!def $altData){
	^throw[${CLASS_NAME}.spec;^$altData;param not specified]
}

$hParams[^hash::create[$hshParams]]

$sTagName[^if(def $hParams.tag_name){$hParams.tag_name}{object}]

$iLocaleID(^hParams.locale_id.int($self.LOCALE_ID))

^if($altData.texts is "hash"){
	^if($altData.texts.[$iLocaleID]){
		$tTextData[$altData.texts.[$iLocaleID]]
	}{
		$tTextData[$altData.texts.[$self.SPECIAL_LOCALE]]
	}
}

^if(!$tTextData && ^altData.link_to_object_id.int(0)){
	$tTextData[^self._getObjectTextData(^altData.link_to_object_id.int(0);$iLocaleID)]
}

$result[
<$sTagName
	object_id="$altData.id"
	type_id="$altData.type_id"
	nesting="$altData.nesting"
	site_id="$altData.site_id"
	^if(def $altData.template_id){template_id="$altData.template_id"}
	^if(def $altData.process_id){process_id="$altData.process_id"}
	$hParams.tag_attr
>
	<dt_update>^self.printDateTime[^date::create[$altData.dt_update]]</dt_update>
	<path>$altData.path</path>
	<full_path>$altData.full_path</full_path>
	^if(def $altData.url){
		<url>$altData.url</url>
	}
	^if($tTextData){
		<name>^taint[as-is][$tTextData.name]</name>
		^if(def $tTextData.window_name){
			<window_name>^taint[as-is][$tTextData.window_name]</window_name>
		}
		^if(def $tTextData.document_name){
			<document_name>^taint[as-is][$tTextData.document_name]</document_name>
		}
	}
	$hParams.tag_body
</$sTagName>
]
#end @printObject[]



@prepareProcess[intProcessID]
$iProcessID(^intProcessID.int(0))

# if process not loaded, loading it
^if(!$self.PROCESSES.[$iProcessID]){
	$tProcess[^self.getProcess[
		$.id($iProcessID)
		$.add_to_hash(true)
	]]
}

# if file not compiled, compiling and executing it code
^if($self.PROCESSES.[$iProcessID].is_Processed){
	^throw[Engine.process;(process: $iProcessID);process already prepared]
}{

#	defining some variables: filename with path and name of main method
	$sProcessFile[$self.PROCESSES_PATH/$self.PROCESSES.[$iProcessID].filename]
	$sProcessMain[process_${iProcessID}_main]

	^bLib:processFile[
		$.file[$sProcessFile]
		$.main[$sProcessMain]
	]

#	adding link to process'es main method to hash
	$self.PROCESSES.[$iProcessID].main[$$sProcessMain]

	$self.PROCESSES.[$iProcessID].is_Processed(true)
}
#end @prepareProcess[]



@runProcess[intProcessID;altAdditionalData]
$iProcessID(^intProcessID.int(0))

# preparing process to run, if it not processed
^if(!$self.PROCESSES.[$iProcessID].is_Processed){
	^self.prepareProcess[$iProcessID]
}

^if($self.PROCESSES.[$iProcessID].main is 'junction'){
	^if(def $altAdditionalData){
		$result[^self.PROCESSES.[$iProcessID].main[$altAdditionalData]]
	}{
		$result[^self.PROCESSES.[$iProcessID].main[]]
	}
}
#end @runProcess[]



###########################################################################
#	Result: string
@parseData[strData]
$result[$strData]
#end @parseData[]



###########################################################################
#	Result: string
@_parseBlock[altData]
$hBlockParams[^self.parseBlockParams[$altData.params]]

$self.BLOCK_ID(^altData.id.int(0))
$self.BLOCK[$altData]

# if specified block's process, running it
^if(^altData.process_id.int(0)){
	$sBlockProcessData[^self.runProcess[^altData.process_id.int(0);$hBlockParams]]
}

# adding parameters for printing block
^hBlockParams.add[
	$.tag_name[$altData.name]
	$.tag_body[$sBlockProcessData]
]

$result[^self.printBlock[$altData;$hBlockParams]]

$self.BLOCK_ID[]
$self.BLOCK[]
#end @_parseBlock[]



###########################################################################
#	Result: string
@parseObjectBlocks[intObjectID]
# if needed, changing current object
^if(^intObjectID.int($self.OBJECT_ID) != $self.OBJECT_ID){
	$iPreviousObjectID($self.OBJECT_ID)
	
	^self.replaceCurrentObject(^intObjectID.int($self.OBJECT_ID))
}

^if(!$self.BLOCKS.[$self.OBJECT_ID].is_Loaded){
	$tBlocks[^self.getBlocks[
		$.object_id($OBJECT_ID)
		$.add_to_hash(true)
	]]
}

$tBlocks[$self.BLOCKS.[$self.OBJECT_ID].order]

^if($tBlocks){
	^tBlocks.menu{
		^if(!^tBlocks.is_parsed_manual.int(0)){
			^self._parseBlock[$tBlocks.fields]
		}
	}
}


^if(^iPreviousObjectID.int(0)){
	^self.replaceCurrentObject(^iPreviousObjectID.int(0))
}
#end @parseObjectBlocks[]



###########################################################################
#	Parameters:
#		$.object_id(int) = 0
#		$.type[string]
#	Result: string
@parseBlocks[strName;hshParams]
$hParams[^hash::create[$hshParams]]

# if needed, changing current object
^if(^hParams.object_id.int($self.OBJECT_ID) != $self.OBJECT_ID){
	$iPreviousObjectID($self.OBJECT_ID)
	
	^self.replaceCurrentObject(^hParams.object_id.int($self.OBJECT_ID))
}


# if object's blocks not loaded, loading it
^if(!$self.BLOCKS.[$self.OBJECT_ID].is_Loaded){
	$tObjectBlocks[^self.getBlocks[
		$.object_id($self.OBJECT_ID)
#		$.add_to_hash(true)
	]]
}


$tObjectBlocks[$self.BLOCKS.[$self.OBJECT_ID].order]


^if($tObjectBlocks){

#	if specified blocks name, parsing blocks by name
	^if(def $strName){
		$self.BLOCKS.[$self.OBJECT_ID].name[^tObjectBlocks.hash[name]]
	
#		getting blocks by name from hash
		$tBlocks[$self.BLOCKS.[$self.OBJECT_ID].name[$strName]]
	}{
		$tBlocks[$tObjectBlocks]
	}
	
#	if specified name of data type, getting data type and selecting blocks by this type
	^if(def $hParams.type){
		$tDataType[^self.getDataType[$.name[$hParams.type]]]
		
		$tBlocks[^tBlocks.select($tBlocks.data_type_id == $tDataType.id)]
	}
	
	^tBlocks.sort{$tBlocks.sort_order}[desc]
	
	^tBlocks.menu{
		^self._parseBlock[$tBlocks.fields]
	}

}

^if(^iPreviousObjectID.int(0)){
	^self.replaceCurrentObject(^iPreviousObjectID.int(0))
}
#end @parseBlocks[]



###########################################################################
#	Result: hash
@parseBlockParams[strBlockParams]
$result[^hash::create[]]

$sBlockParams[^self.parseData[$strBlockParams]]

# creating xdoc-document with params
$xBlockParams[^xdoc::create{<?xml version="1.0" encoding="$request:charset" ?>
	<params>
		^taint[as-is][$sBlockParams]
	</params>
}]

# selecting params
$hBlockParams[^xBlockParams.select[/params/*]]

# creating result hash
^hBlockParams.foreach[sKey;hNode]{
	$result.[$hNode.nodeName][$hNode.firstChild.nodeValue]
}
#end @parseBlockParams[]



###########################################################################
#	Options:
#		$.tag_name[string]
#		$.tag_attr[string]
#		$.tag_body[string]
#		$.parse_data(bool) = true
#	Result: string
@printBlock[altData;hshParams]
$hParams[^hash::create[$hshParams]]

$sTagName[^if(def $hParams.tag_name){$hParams.tag_name}{block}]

^if(^altData.is_not_empty.int(0)){
	^if(^altData.parse_data.bool(true)){
		$sBlockData[^self.parseData[$altData.data]]
	}{
		$sBlockData[$altData.data]
	}
}

# getting name of data type
$tDataType[^self.getDataType[$.id($altData.data_type_id)]]

# if defined method to parse this type of blocks, called this method,
# otherwise printing block data by default template
^if($_printBlock_$sType is "junction"){
	^self._printBlock_$tDataType.name[$altData;$hParams]
}{
	^if($tDataType.name eq "HTML" || $tDataType.name eq "XML"){
		$sBlockData[^taint[optimized-as-is][$sBlockData]]
	}

	$result[
		<$sTagName
			^if($tDataType.name eq "HTML"){
				xmlns="http://www.w3.org/1999/xhtml"
			}
			^taint[as-is][$hParams.tag_attr]>${sBlockData}$hParams.tag_body</$sTagName>
	]
}
#end @printBlock[]



###########################################################################
#	Result: string
@printDateTime[dtBody]
$result[^dtBody.sql-string[]]
#end @printDateTime[]
